package org.hepeng.resiliencedefense.config;

import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Properties;

/**
 * @author he peng
 */

@Getter
public class ResiliencedefenseProperties {

    private static final Logger LOG = LoggerFactory.getLogger(ResiliencedefenseProperties.class);

    public static final String CONFIG_PREFIX = "resiliencedefense";

    public static final String CIRCUIT_BREAKER_ENABLE_KEY = "circuitBreaker.enable";
    public static final String CIRCUIT_BREAKER_FORCE_OPENN_KEY = "circuitBreaker.forceOpen";
    public static final String CIRCUIT_BREAKER_FORCE_CLOSE_KEY = "circuitBreaker.forceClose";
    public static final String CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE_KEY = "circuitBreaker.errorThresholdPercentage";
    public static final String CIRCUIT_BREAKER_ATTEMPT_CLOSE_AFTER_MILLISECONDS_KEY = "circuitBreaker.attemptCloseAfterMilliseconds";

    public static final String EXEC_ISOLATION_STRATEGY_KEY = "exec.isolation.strategy";
    public static final String EXEC_TIMEOUT_IN_MILLISECONDS_KEY = "exec.timeoutInMilliseconds";
    public static final String EXCE_ISOLATION_SEMAPHORE_REJECT_THRESHOLD_KEY = "exec.isolation.semaphore.rejectThreshold";

    public static final String METRICS_TIME_IN_MILLISECONDS = "metrics.timeInMilliseconds";

    public static final String DEFAULT_DEPENDENCY_ID = "default";
    public static final String DEFAULT_API_ID = "default";

    private String dependencyId = DEFAULT_DEPENDENCY_ID;
    private String apiId = DEFAULT_API_ID;

    private ResiliencedefenseProperty<Boolean> circuitBreakerEnable;
    private ResiliencedefenseProperty<Boolean> circuitBreakerForceOpen;
    private ResiliencedefenseProperty<Boolean> circuitBreakerForceClose;
    private ResiliencedefenseProperty<Double> circuitBreakerErrorThresholdPercentage;
    private ResiliencedefenseProperty<Long> circuitBreakerAttemptCloseAfterMilliseconds;

    private ResiliencedefenseProperty<ExecIsolationStrategy> execIsolationStrategy;
    private ResiliencedefenseProperty<Long> execTimeoutInMilliseconds;
    private ResiliencedefenseProperty<Long> execIsolationSemaphoreRejectThreshold;

    public ResiliencedefenseProperties(String dependencyId , String apiId , Properties properties) {
        this.dependencyId = dependencyId;
        this.apiId = apiId;
        this.circuitBreakerEnable = () -> Boolean.valueOf(properties.getProperty(buildConfigKey(dependencyId , apiId , CIRCUIT_BREAKER_ENABLE_KEY) , Boolean.TRUE.toString()));
        this.circuitBreakerForceOpen = () -> Boolean.valueOf(properties.getProperty(buildConfigKey(dependencyId , apiId , CIRCUIT_BREAKER_FORCE_OPENN_KEY) , Boolean.FALSE.toString()));
        this.circuitBreakerForceClose = () -> Boolean.valueOf(properties.getProperty(buildConfigKey(dependencyId , apiId , CIRCUIT_BREAKER_FORCE_CLOSE_KEY) , Boolean.FALSE.toString()));
        this.circuitBreakerErrorThresholdPercentage = () -> Double.valueOf(properties.getProperty(buildConfigKey(dependencyId , apiId , CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE_KEY) , "0.5"));
        this.circuitBreakerAttemptCloseAfterMilliseconds = () -> Long.valueOf(properties.getProperty(buildConfigKey(dependencyId , apiId , CIRCUIT_BREAKER_ATTEMPT_CLOSE_AFTER_MILLISECONDS_KEY) , "12000"));
        this.execIsolationStrategy = () -> ExecIsolationStrategy.valueOf(properties.getProperty(buildConfigKey(dependencyId , apiId , EXEC_ISOLATION_STRATEGY_KEY) , ExecIsolationStrategy.SEMAPHORE.name()));
        this.execTimeoutInMilliseconds = () -> Long.valueOf(properties.getProperty(buildConfigKey(dependencyId , apiId , EXEC_TIMEOUT_IN_MILLISECONDS_KEY) , "1500"));
        this.execIsolationSemaphoreRejectThreshold = () -> Long.valueOf(properties.getProperty(buildConfigKey(dependencyId , apiId , EXCE_ISOLATION_SEMAPHORE_REJECT_THRESHOLD_KEY) , "10"));
    }

    private String buildConfigKey(String dependencyId , String apiId , String suffix) {
        StringBuilder keyBuild = new StringBuilder(CONFIG_PREFIX);
        keyBuild = StringUtils.isBlank(dependencyId) ? keyBuild : keyBuild.append(".").append(dependencyId);
        keyBuild = StringUtils.isBlank(apiId) ? keyBuild : keyBuild.append(".").append(apiId).append(".");
        return keyBuild.append(suffix).toString();
    }

    enum ExecIsolationStrategy {
        SEMAPHORE
    }
}
